/*
This file is part of lAPIn.

lAPIn is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

lAPIn is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with lAPIn.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.opensource.nabaztag;

import java.awt.Color;

/**
 * Describes a choregraphy to be sent.
 * <br />
 * A mix of ears movements and LED flash canbe used.
 */
public class Choregraphy {

    /**
     * A step in the choregraphy.
     * <br />
     * Can affect ears position or LED color.
     */
    public static class Command {

        private static final String SEPARATOR = ",";
        private static final String LED_KEYWORD = "led";
        private static final String MOTOR_KEYWORD = "motor";

        private final String command;

        /**
         * Constructs using a led sequence.
         *
         * @param time when to start the sequence
         * @param led LED to manipulate
         * @param color color of the LED
         */
        public Command(final int time, final Rabbit.LED led, final Color color) {
            this.command = time+Command.SEPARATOR+Command.LED_KEYWORD+Command.SEPARATOR+led.ordinal()+Command.SEPARATOR+
                    color.getRed()+Command.SEPARATOR+color.getGreen()+Command.SEPARATOR+color.getBlue();
        }

        /**
         * Constructs using an ear sequence.
         *
         * @param time when to start the sequence
         * @param ear ear to manipulate
         * @param angle rotation angle
         * @param rotation rotation motion
         */
        public Command(final int time, final Rabbit.EAR ear, final int angle, final Rabbit.EAR.ROTATION rotation) {
            if (angle < 0 || angle > 180) {
                throw new IllegalArgumentException("angle must be comprised between 0-180");
            }

            this.command = time+Command.SEPARATOR+Command.MOTOR_KEYWORD+Command.SEPARATOR+asEarCode(ear)+Command.SEPARATOR+
                    angle+Command.SEPARATOR+"0"+Command.SEPARATOR+asRotationCode(rotation);
        }

        /**
         * Translates Rabbit.EAR into Nabaztag ear code.
         *
         * @param ear ear to translate
         * @return associated Nabaztag code
         */
        protected String asEarCode(final Rabbit.EAR ear) {
            return ear == Rabbit.EAR.LEFT?"1":"0";
        }

        /**
         * Translates Rabbit.EAR.ROTATION into Nabaztag rotation code.
         *
         * @param rotation rotation to translate
         * @return associated Nabaztag code
         */
        protected String asRotationCode(final Rabbit.EAR.ROTATION rotation) {
            return rotation == Rabbit.EAR.ROTATION.CLOCKWISE?"1":"0";
        }

        /**
         * Returns the full command as a Nabaztag sequence.
         */
        public String getCommand() {
            return this.command;
        }

    }

    private final int tempo;
    private final Command[] commands;

    /**
     * Constructs a choregraphy with specified tempo and some commands.
     *
     * @param tempo rythm in Hz
     * @param commands sequence of commands
     */
    public Choregraphy(final int tempo, final Command ... commands) {
        if (tempo < 0) {
            throw new IllegalArgumentException("tempo must be positive");
        }

        this.tempo = tempo;
        this.commands = commands;
    }

    /**
     * Returns the choregraphy as a Nabaztag representation.
     *
     * @return the choregraphy as a Nabaztag representation
     */
    public String getCommand() {
        final StringBuffer fullCommand = new StringBuffer(String.valueOf(this.tempo));
        for (final Command command : this.commands) {
            fullCommand.append(Command.SEPARATOR+command.getCommand());
        }
        return fullCommand.toString();
    }

}
